package com.meida.common.poi;

import cn.afterturn.easypoi.cache.WordCache;
import cn.afterturn.easypoi.entity.ImageEntity;
import cn.afterturn.easypoi.util.PoiPublicUtil;
import cn.afterturn.easypoi.word.entity.MyXWPFDocument;
import cn.afterturn.easypoi.word.entity.params.ExcelListEntity;
import cn.afterturn.easypoi.word.parse.ParseWord07;
import cn.afterturn.easypoi.word.parse.excel.ExcelEntityParse;
import cn.afterturn.easypoi.word.parse.excel.ExcelMapParse;
import com.meida.common.utils.FlymeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.*;

public class MyParseWord07 {
    private static final Logger LOGGER = LoggerFactory.getLogger(ParseWord07.class);

    public MyParseWord07() {
    }

    private void changeValues(XWPFParagraph paragraph, XWPFRun currentRun, String currentText, List<Integer> runIndex, Map<String, Object> map) throws Exception {
        Object obj = PoiPublicUtil.getRealValue(currentText, map);
        if (obj instanceof ImageEntity) {
            currentRun.setText("", 0);
            if (currentText.indexOf("logo") >= 0) {
                ImageEntity img = (ImageEntity) obj;
                if (FlymeUtils.isNotEmpty(img)&&FlymeUtils.isNotEmpty(img.getUrl())) {
                    Object[] isAndType = PoiPublicUtil.getIsAndType(img);
                    paragraph.setAlignment(ParagraphAlignment.CENTER);
                    //字节数组与程序之间的管道
                    if (FlymeUtils.isNotEmpty(isAndType)) {
                        InputStream is = new ByteArrayInputStream((byte[]) ((byte[]) isAndType[0]));
                        XWPFPicture picture = currentRun.addPicture(is, (Integer) isAndType[1], System.currentTimeMillis() + "", Units.toEMU(img.getWidth()), Units.toEMU(img.getHeight()));
                        for (XWPFHeader header : currentRun.getDocument().getHeaderList()) {
                            // 这段必须有，不然打开的logo图片不显示
                            for (XWPFPictureData picturedata : header.getAllPackagePictures()) {
                                String id = header.getRelationId(picturedata);
                                if (id != null) {
                                    picture.getCTPicture().getBlipFill().getBlip().setEmbed(id);
                                }
                            }
                        }
                        currentRun.addTab();
                        is.close();
                    }
                }
            } else {
                ExcelMapParse.addAnImage((ImageEntity) obj, currentRun);
            }
        } else {
            currentText = obj.toString();
            PoiPublicUtil.setWordText(currentRun, currentText);
        }

        for (int k = 0; k < runIndex.size(); ++k) {
            ((XWPFRun) paragraph.getRuns().get((Integer) runIndex.get(k))).setText("", 0);
        }
        runIndex.clear();
    }

    private Object checkThisTableIsNeedIterator(XWPFTableCell cell, Map<String, Object> map) throws Exception {
        String text = cell.getText().trim();
        if (text != null && text.contains("fe:") && text.startsWith("{{")) {
            text = text.replace("!fe:", "").replace("$fe:", "").replace("fe:", "").replace("{{", "");
            String[] keys = text.replaceAll("\\s{1,}", " ").trim().split(" ");
            Object result = PoiPublicUtil.getParamsValue(keys[0], map);
            return Objects.nonNull(result) ? result : new ArrayList(0);
        } else {
            return null;
        }
    }

    private void parseAllParagraphic(List<XWPFParagraph> paragraphs, Map<String, Object> map) throws Exception {
        for (int i = 0; i < paragraphs.size(); ++i) {
            XWPFParagraph paragraph = (XWPFParagraph) paragraphs.get(i);
            if (paragraph.getText().indexOf("{{") != -1) {
                this.parseThisParagraph(paragraph, map);
            }
        }

    }

    private void parseThisParagraph(XWPFParagraph paragraph, Map<String, Object> map) throws Exception {
        XWPFRun currentRun = null;
        String currentText = "";
        Boolean isfinde = false;
        List<Integer> runIndex = new ArrayList();

        for (int i = 0; i < paragraph.getRuns().size(); ++i) {
            XWPFRun run = (XWPFRun) paragraph.getRuns().get(i);
            String text = run.getText(0);
            if (!StringUtils.isEmpty(text)) {
                if (isfinde) {
                    currentText = currentText + text;
                    if (currentText.indexOf("{{") == -1) {
                        isfinde = false;
                        runIndex.clear();
                    } else {
                        runIndex.add(i);
                    }

                    if (currentText.indexOf("}}") != -1) {
                        this.changeValues(paragraph, currentRun, currentText, runIndex, map);
                        currentText = "";
                        isfinde = false;
                    }
                } else if (text.indexOf("{{") >= 0) {
                    currentText = text;
                    isfinde = true;
                    currentRun = run;
                } else {
                    currentText = "";
                }

                if (currentText.indexOf("}}") != -1) {
                    this.changeValues(paragraph, currentRun, currentText, runIndex, map);
                    isfinde = false;
                }
            }
        }

    }

    private void parseThisRow(List<XWPFTableCell> cells, Map<String, Object> map) throws Exception {
        Iterator var3 = cells.iterator();

        while (var3.hasNext()) {
            XWPFTableCell cell = (XWPFTableCell) var3.next();
            this.parseAllParagraphic(cell.getParagraphs(), map);
        }

    }

    private void parseThisTable(XWPFTable table, Map<String, Object> map) throws Exception {
        for (int i = 0; i < table.getNumberOfRows(); ++i) {
            XWPFTableRow row = table.getRow(i);
            List<XWPFTableCell> cells = row.getTableCells();
            Object listobj = this.checkThisTableIsNeedIterator((XWPFTableCell) cells.get(0), map);
            if (listobj == null) {
                this.parseThisRow(cells, map);
            } else if (listobj instanceof ExcelListEntity) {
                (new ExcelEntityParse()).parseNextRowAndAddRow(table, i, (ExcelListEntity) listobj);
                i = i + ((ExcelListEntity) listobj).getList().size() - 1;
            } else {
                ExcelMapParse.parseNextRowAndAddRow(table, i, (List) listobj);
                i = i + ((List) listobj).size() - 1;
            }
        }

    }

    public XWPFDocument parseWord(String url, Map<String, Object> map) throws Exception {
        MyXWPFDocument doc = WordCache.getXWPFDocument(url);
        this.parseWordSetValue(doc, map);
        return doc;
    }

    public XWPFDocument parseWord(String url, List<Map<String, Object>> list) throws Exception {
        if (list.size() == 1) {
            return this.parseWord(url, (Map) list.get(0));
        } else if (list.size() == 0) {
            return null;
        } else {
            MyXWPFDocument doc = WordCache.getXWPFDocument(url);
            this.parseWordSetValue(doc, (Map) list.get(0));
            doc.createParagraph().setPageBreak(true);

            for (int i = 1; i < list.size(); ++i) {
                MyXWPFDocument tempDoc = WordCache.getXWPFDocument(url);
                this.parseWordSetValue(tempDoc, (Map) list.get(i));
                tempDoc.createParagraph().setPageBreak(true);
                this.appendBody(doc, tempDoc);
                //doc.getDocument().addNewBody().set(tempDoc.getDocument().getBody());
            }

            return doc;
        }
    }

    public void appendBody(XWPFDocument src, XWPFDocument append) throws Exception {
        CTBody src1Body = src.getDocument().getBody();
        CTBody src2Body = append.getDocument().getBody();

        List<XWPFPictureData> allPictures = append.getAllPictures();
        // 记录图片合并前及合并后的ID
        Map<String, String> map = new HashMap();
        for (XWPFPictureData picture : allPictures) {
            String before = append.getRelationId(picture);
            //将原文档中的图片加入到目标文档中
            String after = src.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);

            map.put(before, after);
        }

        appendBody(src1Body, src2Body, map);

    }

    private void appendBody(CTBody src, CTBody append, Map<String, String> map) throws Exception {
        XmlOptions optionsOuter = new XmlOptions();
        optionsOuter.setSaveOuter();
        String appendString = append.xmlText(optionsOuter);

        String srcString = src.xmlText();
        String prefix = srcString.substring(0, srcString.indexOf(">") + 1);
        String mainPart = srcString.substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<"));
        String sufix = srcString.substring(srcString.lastIndexOf("<"));
        String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));

        if (map != null && !map.isEmpty()) {
            //对xml字符串中图片ID进行替换
            for (Map.Entry<String, String> set : map.entrySet()) {
                addPart = addPart.replace(set.getKey(), set.getValue());
            }
        }
        //将两个文档的xml内容进行拼接
        CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix);

        src.set(makeBody);
    }

    public void parseWord(XWPFDocument document, Map<String, Object> map) throws Exception {
        this.parseWordSetValue((MyXWPFDocument) document, map);
    }

    private void parseWordSetValue(MyXWPFDocument doc, Map<String, Object> map) throws Exception {
        //TODO 1处理自定义标签
        EasyPoiPlus poi = new EasyPoiPlus();
        poi.doEasyPoiPlus(doc, map);
        this.parseAllParagraphic(doc.getParagraphs(), map);
        this.parseHeaderAndFoot(doc, map);
        Iterator itTable = doc.getTablesIterator();

        while (itTable.hasNext()) {
            XWPFTable table = (XWPFTable) itTable.next();
            //TODO 2 自定义循环中的table 填充属性后text为空，造成POI的标签不执行，暂时注释掉这里的代码
            //if (table.getText().indexOf("{{") != -1) {
            this.parseThisTable(table, map);
            //}
        }

    }

    private void parseHeaderAndFoot(MyXWPFDocument doc, Map<String, Object> map) throws Exception {
        List<XWPFHeader> headerList = doc.getHeaderList();
        Iterator var4 = headerList.iterator();

        while (var4.hasNext()) {
            XWPFHeader xwpfHeader = (XWPFHeader) var4.next();
            List<XWPFTable> itTable = xwpfHeader.getTables();

            for (XWPFTable xwpfTable : itTable) {
                this.parseThisTable(xwpfTable, map);
            }
            for (int i = 0; i < xwpfHeader.getListParagraph().size(); ++i) {
                this.parseThisParagraph((XWPFParagraph) xwpfHeader.getListParagraph().get(i), map);
            }

        }

        List<XWPFFooter> footerList = doc.getFooterList();
        Iterator var9 = footerList.iterator();

        while (var9.hasNext()) {
            XWPFFooter xwpfFooter = (XWPFFooter) var9.next();

            for (int i = 0; i < xwpfFooter.getListParagraph().size(); ++i) {
                this.parseThisParagraph((XWPFParagraph) xwpfFooter.getListParagraph().get(i), map);
            }
        }

    }
}